package org.truenewx.tnxjee.webmvc.util;

import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;
import org.truenewx.tnxjee.core.Strings;
import org.truenewx.tnxjee.core.enums.EnumDictResolver;
import org.truenewx.tnxjee.core.enums.EnumItem;
import org.truenewx.tnxjee.core.enums.annotation.EnumProperty;
import org.truenewx.tnxjee.core.enums.annotation.SimpleEnumType;
import org.truenewx.tnxjee.core.util.BeanPropertyMeta;
import org.truenewx.tnxjee.model.validation.constraint.RegionCode;
import org.truenewx.tnxjee.service.spec.region.Region;
import org.truenewx.tnxjee.service.spec.region.RegionSource;

import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.function.BiConsumer;

/**
 * 附加字段工具类
 */
public class AttachFieldUtil {

    private AttachFieldUtil() {
    }

    public static Object getAttachedCaptionValue(BeanPropertyMeta meta, Object rawValue,
            EnumDictResolver enumDictResolver, @Nullable RegionSource regionSource, String subType, Locale locale) {
        if (meta.isMulti()) {
            Map<String, Object> captionMap = new HashMap<>();
            if (rawValue instanceof Object[] array) {
                for (Object element : array) {
                    if (element != null) {
                        String caption = getAttachedCaptionOfSingle(element, meta.getAnnotation(), enumDictResolver,
                                regionSource, subType, locale);
                        if (caption != null) {
                            captionMap.put(element.toString(), caption);
                        }
                    }
                }
            } else if (rawValue instanceof Collection<?> collection) {
                for (Object element : collection) {
                    if (element != null) {
                        String caption = getAttachedCaptionOfSingle(element, meta.getAnnotation(), enumDictResolver,
                                regionSource, subType, locale);
                        if (caption != null) {
                            captionMap.put(element.toString(), caption);
                        }
                    }
                }
            }
            return captionMap.isEmpty() ? null : captionMap;
        } else {
            return getAttachedCaptionOfSingle(rawValue, meta.getAnnotation(), enumDictResolver, regionSource, subType,
                    locale);
        }
    }

    private static String getAttachedCaptionOfSingle(Object rawValue, Annotation annotation,
            EnumDictResolver enumDictResolver, @Nullable RegionSource regionSource, String subType, Locale locale) {
        String caption = null;
        boolean resolved = false;
        if (rawValue != null) { // null值一定没有附加的显示名称
            if (rawValue instanceof Enum<?> value) {
                caption = enumDictResolver.getText(value, subType, locale);
                resolved = true;
            } else {
                Class<?> rawClass = rawValue.getClass();
                if (Proxy.isProxyClass(rawClass)) {
                    rawClass = rawClass.getInterfaces()[0];
                }
                String value = rawValue.toString();
                SimpleEnumType simpleEnumType = rawClass.getAnnotation(SimpleEnumType.class);
                if (simpleEnumType != null) {
                    String type = simpleEnumType.name();
                    if (StringUtils.isBlank(type)) {
                        type = rawClass.getSimpleName();
                    }
                    caption = enumDictResolver.getText(type, subType, value, locale);
                    resolved = true;
                } else if (annotation instanceof EnumProperty enumProperty) {
                    // 优先使用结果过滤注解中指定的子类型名，如果没有则使用枚举属性注解上的子类型名
                    if (StringUtils.isBlank(subType)) {
                        subType = enumProperty.subType();
                    }
                    caption = enumDictResolver.getText(enumProperty.type(), subType, value, locale);
                    resolved = true;
                } else if (annotation instanceof RegionCode regionCode) {
                    if (regionSource != null && StringUtils.isNotBlank(value)) {
                        Region region = regionSource.getRegion(value, locale);
                        if (region != null) {
                            caption = region.getCaption(regionCode.withSuffix());
                            if (caption != null) {
                                StringBuilder sb = new StringBuilder(caption);
                                Region parentRegion = region.getParent();
                                while (parentRegion != null
                                        && parentRegion.getLevel() >= regionCode.captionBeginLevel()) {
                                    String parentCaption = parentRegion.getCaption(regionCode.withSuffix());
                                    if (parentCaption != null) {
                                        sb.insert(0, parentCaption);
                                    }
                                    parentRegion = parentRegion.getParent();
                                }
                                caption = sb.toString();
                            }
                            resolved = true;
                        }
                    }
                }
            }
        }
        // 确保已经处理的结果不为null
        if (caption == null && resolved) {
            caption = Strings.EMPTY;
        }
        return caption;
    }

    private static String getAttachedFieldName(String rawPropertyName, String attachedPropertyName) {
        return rawPropertyName + Strings.UNDERLINE + attachedPropertyName;
    }

    public static String getAttachedCaptionFieldName(String rawPropertyName) {
        return getAttachedFieldName(rawPropertyName, "caption");
    }

    /**
     * 遍历单值属性（非数组）的附加属性
     *
     * @param meta     属性名
     * @param rawValue 属性值
     * @param locale   地区
     * @param consumer 附加字段消费者
     */
    public static void loopAttachedProperty(BeanPropertyMeta meta, Object rawValue, EnumDictResolver enumDictResolver,
            Locale locale, BiConsumer<String, Object> consumer) {
        Class<?> rawClass = meta.getRawClass();
        // 枚举类型或枚举类型集合附加枚举中的额外属性
        SimpleEnumType simpleEnumType = rawClass.getAnnotation(SimpleEnumType.class);
        if (rawClass.isEnum() || simpleEnumType != null) {
            Map<String, Object> attachment = null;
            if (meta.isMulti()) {
                attachment = new HashMap<>();
                if (rawValue instanceof Enum[]) {
                    Enum<?>[] array = (Enum<?>[]) rawValue;
                    for (Enum<?> element : array) {
                        EnumItem enumItem = getEnumItem(rawClass, element, enumDictResolver, simpleEnumType, locale);
                        fillEnumItemAttachFields(meta, rawValue, attachment, enumItem);
                    }
                } else if (rawValue instanceof Collection<?> collection) {
                    for (Object element : collection) {
                        EnumItem enumItem = getEnumItem(rawClass, element, enumDictResolver, simpleEnumType, locale);
                        fillEnumItemAttachFields(meta, rawValue, attachment, enumItem);
                    }
                }
            } else {
                EnumItem enumItem = getEnumItem(rawClass, rawValue, enumDictResolver, simpleEnumType, locale);
                if (enumItem != null) {
                    attachment = enumItem.getAttachment();
                }
            }
            if (attachment != null) {
                attachment.forEach((key, value) -> {
                    String attachedFieldName = AttachFieldUtil.getAttachedFieldName(meta.getName(), key);
                    consumer.accept(attachedFieldName, value);
                });
            }
        }
    }

    private static EnumItem getEnumItem(Class<?> rawClass, Object rawValue, EnumDictResolver enumDictResolver,
            SimpleEnumType simpleEnumType, Locale locale) {
        if (rawClass.isEnum()) {
            return enumDictResolver.getEnumItem((Enum<?>) rawValue, locale);
        } else if (simpleEnumType != null) {
            String type = simpleEnumType.name();
            if (StringUtils.isBlank(type)) {
                type = rawClass.getSimpleName();
            }
            String key = rawValue.toString();
            return enumDictResolver.getEnumItem(type, null, key, locale);
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private static void fillEnumItemAttachFields(BeanPropertyMeta meta, Object rawValue, Map<String, Object> attachment,
            EnumItem enumItem) {
        if (enumItem != null) {
            Map<String, Object> elementAttachment = enumItem.getAttachment();
            if (elementAttachment != null) {
                for (Map.Entry<String, Object> entry : elementAttachment.entrySet()) {
                    String key = entry.getKey();
                    String fieldName = AttachFieldUtil.getAttachedFieldName(meta.getName(), key);
                    Map<String, Object> valueMap = (Map<String, Object>) attachment.computeIfAbsent(fieldName,
                            k -> new HashMap<>());
                    valueMap.put(rawValue.toString(), entry.getValue());
                }
            }
        }
    }

}
